package net.chrisrichardson.ec2deployer.cluster

import org.apache.commons.logging.*
import net.chrisrichardson.ec2deployer.core.EC2
import net.chrisrichardson.ec2deployer.core.EC2Server
import net.chrisrichardson.ec2deployer.core.CloudManager


class MultipleInstancesTopology implements ClusterTopology {

    def Log logger = LogFactory.getLog(getClass())

    ClusterHosts allocateServers(CloudManager ec2, ClusterSpec spec, reuseRunningInstances) {

        def extraParams = [:]
        if (spec.ebsVolume?.useExistingVolume) {
            extraParams = ["Placement.AvailabilityZone" : ec2.getAvailabilityZoneOfEbsVolume(spec.ebsVolume)]
        }

        EC2Server databaseServer = ec2.newServers(1, spec.masterDatabaseInstanceType, extraParams + securityGroup(spec, "database"))[0]
        List<EC2Server>  mySqlSlaves = allocateMySqlSlaves(ec2, spec, databaseServer)
        List<EC2Server> appServers = ec2.newServers(spec.numberOfTomcats, spec.tomcatInstanceType, sameZoneAsAndWithSecurityGroup(spec, databaseServer, "appServers"))
        EC2Server apacheServer = ec2.newServers(1, spec.apacheInstanceType, sameZoneAsAndWithSecurityGroup(spec, databaseServer, "webServers"))[0]
        EC2Server jmeterInstance = ec2.newServers(1, spec.jmeterInstanceType, sameZoneAsAndWithSecurityGroup(spec, databaseServer, "jmeter"))[0]
        List<EC2Server> terracottaInstances = ec2.newServers(spec.numberOfTerracottaHosts, spec.tomcatInstanceType, sameZoneAsAndWithSecurityGroup(spec, databaseServer, "terracottaServers"))
        
        return new ClusterHosts(databaseServer: databaseServer,
                mySqlSlaves: mySqlSlaves,
                tomcats: appServers,
                apacheServer: apacheServer,
                jmeter: jmeterInstance,
                terracottaHosts: terracottaInstances  // Need its own type
                )
    }


    List<EC2Server> allocateMySqlSlaves(CloudManager ec2, ClusterSpec spec, EC2Server mainServer) {
        if (spec.useHaSlave)
            return ec2.newServersElsewhere(1, spec.slaveDatabaseInstanceType, mainServer, securityGroup(spec, "dbslaves")) +
                    ec2.newServers(spec.numberOfSlaves - 1, spec.slaveDatabaseInstanceType, sameZoneAsAndWithSecurityGroup(spec, mainServer, "dbslaves"))
        else
            return ec2.newServers(spec.numberOfSlaves, spec.slaveDatabaseInstanceType, sameZoneAsAndWithSecurityGroup(spec, mainServer, "dbslaves"))
    }

    private Map<String, String> sameZoneAsAndWithSecurityGroup(ClusterSpec spec, EC2Server mainServer, String securityGroupSuffix) {
        return ["Placement.AvailabilityZone": mainServer.availabilityZone] + securityGroup(spec, securityGroupSuffix)
    }

    Map<String, String> securityGroup(ClusterSpec spec, String tierSuffix) {
        if (spec.securityGroupPrefix)
            return ["SecurityGroup.1" : spec.securityGroupPrefix + "-" + tierSuffix]
        else
            return [:]
    }

}